package core.filter.type;

import java.util.LinkedList;
import java.util.List;

import tool.Complex;
import tool.Pair;

import core.FilterFactory;
import core.filter.BaseFilter;

public class Butterworth extends BaseFilter{

	private List<Complex> polesList = null;
	private long n;
	
	static {
		FilterFactory.registerFilterType(FilterTypes.BUTTERWORTH, new Butterworth());
	}
	
	protected void calculateN() {
		double nn = Math.log10((Math.pow(10, 0.1*suppressionR)-1) / (Math.pow(10, 0.1*suppressionP)-1));  
		double n = (2*Math.log10(frequencyR/frequencyP));
		long temp = Math.round(nn/n);
		if(temp != nn && 10*temp <= 10*nn/n){
			this.n = temp + 1;
			return;
		}
		this.n = temp;
	}

	protected double getFrequencyLimit(long n) {
		double delimeter = Math.pow((Math.pow(10,0.1*suppressionP)-1), (1./(2*n)));
		return frequencyP/delimeter;
	}
	
	@Override
	public List<Complex> getPolesList() {
				//rzad filtru
		double frequencyLimit = getFrequencyLimit(n);
		System.out.println("W3db= "+frequencyLimit/1000);
		if(polesList == null) {
			polesList = new LinkedList<Complex>();
			for(int i=1; i <= n; i++){
				double a = Math.PI/2 + Math.PI/(2*n) + (i-1)*Math.PI/n;
				Complex comp = new Complex(0, -1).times(a).exp();
				polesList.add(comp.times(frequencyLimit/1000));
			}
		}
		return polesList;
	}
	
	public List<Pair> getTransmittance(List<Double> list) {
		List<Pair> resultList = new LinkedList<Pair>();
		calculateN();	
		System.out.println("Rzad: "+n);
		getPolesList();
		System.out.println("Bieguny:");
		for(Complex comp : polesList){
			System.out.println(comp.toString());
		}
		for (Double signal : list) {
			Complex comp = getAnalogTrans(signal/frequencyP);
			resultList.add(new Pair(signal, comp));
		}
		return resultList;
	}
	
	private Complex getPolesRatio(List<Complex> list, long n) {
		Complex ratio = new Complex(1, 0);
		for (Complex pole : list) {
			ratio = ratio.times(pole.times(-1));
		}
		return ratio;
	}
	
	private Complex getDenominator(Object signal, List<Complex> polesList) {
		Complex result = new Complex(1, 0);
		for (Complex pole : polesList) {
			if(signal instanceof Double)
				result = result.times(pole.times(-1).addComplex(new Complex((Double)signal, 0)));
			else if(signal instanceof Complex)
				result = result.times(pole.times(-1).addComplex((Complex)signal));
			else if(signal instanceof Complex) {
				result = result.times(pole.times(-1).addComplex((Complex) signal));
			}
		}
		return result;
	}
	
	private Complex getAnalogTrans(Double signal) {
		return getPolesRatio(polesList, n).division(getDenominator(signal, polesList));
	}
	
	private Complex getDigitalTrans(Complex signal) {
		return getPolesRatio(polesList, n).division(getDenominator(signal, polesList));
	}
}
